#include <Python.h>
#include "pyfootprint.h"
#include "pin.h"
#include "line.h"
#include "rect.h"
#include <iostream>

int footprints_allocated = 0;

static void
PyApiFootprint_dealloc(PyApiFootprint* self)
{
	/*
		Footprints that are added to the library are left allocated.
		TODO: fix?
	*/
	footprints_allocated--;
	//std::cerr<<"PyApiFootprint_dealloc(): footprints_allocated="<<footprints_allocated<<std::endl;
	delete self->footprint;
	self->footprint = NULL;
    self->ob_type->tp_free((PyObject*)self);
}

static PyObject *
PyApiFootprint_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
	footprints_allocated++;
	//std::cerr<<"PyApiFootprint_new(): footprints_allocated="<<footprints_allocated<<std::endl;
    PyApiFootprint *self;

    self = (PyApiFootprint *)type->tp_alloc(type, 0);
    if (self != NULL) {
		self->footprint = new Footprint();
    }

    return (PyObject *)self;
}

static PyObject *
PyApiFootprint_getname(PyApiFootprint *self, void *closure)
{
	if(!self->footprint){
		PyErr_SetString(PyExc_RuntimeError, "!self->footprint");
		return NULL;
	}
	return Py_BuildValue("s", (const char*)self->footprint->m_name.fn_str());
}

static int
PyApiFootprint_setname(PyApiFootprint *self, PyObject *value, void *closure)
{
	/*if (value == NULL) {
		PyErr_SetString(PyExc_TypeError, "Cannot delete the first attribute");
		return -1;
	}*/
	if(!self->footprint){
		PyErr_SetString(PyExc_RuntimeError, "!self->footprint");
		return NULL;
	}

	// This will raise a TypeError if it's not a string
	const char *string = PyString_AsString(value);
	if(string==NULL) return -1;

	self->footprint->m_name = wxString(string, wxConvUTF8);

	return 0;
}

static PyObject *
PyApiFootprint_getsubname(PyApiFootprint *self, void *closure)
{
	if(!self->footprint){
		PyErr_SetString(PyExc_RuntimeError, "!self->footprint");
		return NULL;
	}
	return Py_BuildValue("s", (const char*)self->footprint->m_subname.fn_str());
}

static int
PyApiFootprint_setsubname(PyApiFootprint *self, PyObject *value, void *closure)
{
	if(!self->footprint){
		PyErr_SetString(PyExc_RuntimeError, "!self->footprint");
		return NULL;
	}

	// This will raise a TypeError if it's not a string
	const char *string = PyString_AsString(value);
	if(string==NULL) return -1;

	self->footprint->m_subname = wxString(string, wxConvUTF8);

	return 0;
}

static PyObject *
PyApiFootprint_getside(PyApiFootprint *self, void *closure)
{
	if(!self->footprint){
		PyErr_SetString(PyExc_RuntimeError, "!self->footprint");
		return NULL;
	}
	const char *string = NULL;
	if(self->footprint->m_side == TOP) string = "top";
	else if(self->footprint->m_side == BOTTOM) string = "bottom";
	else if(self->footprint->m_side == UNDEFINED) string = "undefined";
	else{
		PyErr_SetString(PyExc_RuntimeError, "invalid side value");
		return NULL;
	}
	return Py_BuildValue("s", string);
}

static int
PyApiFootprint_setside(PyApiFootprint *self, PyObject *value, void *closure)
{
	if(!self->footprint){
		PyErr_SetString(PyExc_RuntimeError, "!self->footprint");
		return NULL;
	}

	// This will raise a TypeError if it's not a string
	const char *string = PyString_AsString(value);
	if(string==NULL) return -1;

	if(strcmp(string, "top")==0) self->footprint->m_side = TOP;
	else if(strcmp(string, "bottom")==0) self->footprint->m_side = BOTTOM;
	else return -1;

	return 0;
}

static PyGetSetDef PyApiFootprint_getseters[] = {
    {"name", 
     (getter)PyApiFootprint_getname, (setter)PyApiFootprint_setname,
     "name",
     NULL},

    {"subname", 
     (getter)PyApiFootprint_getsubname, (setter)PyApiFootprint_setsubname,
     "subname",
     NULL},

    {"side", 
     (getter)PyApiFootprint_getside, (setter)PyApiFootprint_setside,
     "side of board ('top'/'bottom'/'undefined')",
     NULL},

    {NULL}  /* Sentinel */
};

static PyObject *
PyApiFootprint_add_pin(PyApiFootprint* self, PyObject *args)
{
	const char *num_c;
	const char *name_c;
	const char *type_c;
	int x, y;
	int mark;
	if(!self->footprint){
		PyErr_SetString(PyExc_RuntimeError, "!self->footprint");
		return NULL;
	}

	if(!PyArg_ParseTuple(args, "sss(ii)i", &num_c, &name_c, &type_c, &x, &y, &mark)){
		PyErr_SetString(PyExc_RuntimeError, "wrong parameters");
		return NULL;
	}
	
	//std::cerr<<"add pin at ("<<x<<","<<y<<")"<<std::endl;
	
	Pin *pin = new Pin();
	if(pin==NULL){
		PyErr_SetString(PyExc_RuntimeError, "out of memory?");
		return NULL;
	}

	pin->m_num = wxString(num_c, wxConvUTF8);
	pin->m_name = wxString(name_c, wxConvUTF8);
	if(strcmp(type_c, "through_hole")==0)
		pin->m_type = PIN_THROUGH_HOLE;
	else if(strcmp(type_c, "through_hole_invisible")==0)
		pin->m_type = PIN_THROUGH_HOLE_INVISIBLE;
	else{
		PyErr_SetString(PyExc_RuntimeError, "invalid type (has to be through_hole or through_hole_invisible)");
		delete pin;
		return NULL;
	}
	pin->m_x = x;
	pin->m_y = y;
	pin->m_mark = mark;
	
	self->footprint->m_pins.Add(pin, NULL);

	Py_INCREF(Py_None);
	return Py_None;
}

static PyObject *
PyApiFootprint_add_graphic_line(PyApiFootprint* self, PyObject *args)
{
	int x1, y1;
	int x2, y2;
	if(!self->footprint){
		PyErr_SetString(PyExc_RuntimeError, "!self->footprint");
		return NULL;
	}

	if(!PyArg_ParseTuple(args, "(ii)(ii)", &x1, &y1, &x2, &y2)){
		PyErr_SetString(PyExc_RuntimeError, "wrong parameters");
		return NULL;
	}
	
	Line *line = new Line();
	if(line==NULL){
		PyErr_SetString(PyExc_RuntimeError, "out of memory?");
		return NULL;
	}
	
	line->m_x1 = x1;
	line->m_y1 = y1;
	line->m_x2 = x2;
	line->m_y2 = y2;
	
	self->footprint->m_graphics.Add(line, NULL);

	Py_INCREF(Py_None);
	return Py_None;
}

static PyObject *
PyApiFootprint_add_graphic_rect(PyApiFootprint* self, PyObject *args)
{
	int x, y;
	int w, h;
	if(!self->footprint){
		PyErr_SetString(PyExc_RuntimeError, "!self->footprint");
		return NULL;
	}

	if(!PyArg_ParseTuple(args, "(ii)(ii)", &x, &y, &w, &h)){
		PyErr_SetString(PyExc_RuntimeError, "wrong parameters");
		return NULL;
	}
	
	Rect *rect = new Rect(BoardRect(x,y,w,h));
	if(rect==NULL){
		PyErr_SetString(PyExc_RuntimeError, "out of memory?");
		return NULL;
	}
	
	self->footprint->m_graphics.Add(rect, NULL);

	Py_INCREF(Py_None);
	return Py_None;
}

static PyObject *
PyApiFootprint_add_area_rect(PyApiFootprint* self, PyObject *args)
{
	int x, y;
	int w, h;
	if(!self->footprint){
		PyErr_SetString(PyExc_RuntimeError, "!self->footprint");
		return NULL;
	}

	if(!PyArg_ParseTuple(args, "(ii)(ii)", &x, &y, &w, &h)){
		PyErr_SetString(PyExc_RuntimeError, "wrong parameters");
		return NULL;
	}
	
	Rect *rect = new Rect(BoardRect(x,y,w,h));
	if(rect==NULL){
		PyErr_SetString(PyExc_RuntimeError, "out of memory?");
		return NULL;
	}
	
	self->footprint->m_block_area.Add(rect, NULL);

	Py_INCREF(Py_None);
	return Py_None;
}

static PyMethodDef PyApiFootprint_methods[] = {
    {"add_pin", (PyCFunction)PyApiFootprint_add_pin, METH_VARARGS,
     "Add pin"},
    {"add_graphic_line", (PyCFunction)PyApiFootprint_add_graphic_line, METH_VARARGS,
     "Add visible line"},
    {"add_graphic_rect", (PyCFunction)PyApiFootprint_add_graphic_rect, METH_VARARGS,
     "Add visible rect"},
    {"add_block_rect", (PyCFunction)PyApiFootprint_add_area_rect, METH_VARARGS,
     "Add area rect"},
    {NULL}
};

/*static PyMemberDef PyApiFootprint_members[] = {
    {"number", T_INT, offsetof(PyApiFootprint, number), 0,
     "a number"},
    {NULL}
};*/

PyTypeObject PyApiFootprintType = {
    PyObject_HEAD_INIT(NULL)
    0,                         /*ob_size*/
    "juku.footprint",             /*tp_name*/
    sizeof(PyApiFootprint),             /*tp_basicsize*/
    0,                         /*tp_itemsize*/
    (destructor)PyApiFootprint_dealloc, /*tp_dealloc*/
    0,                         /*tp_print*/
    0,                         /*tp_getattr*/
    0,                         /*tp_setattr*/
    0,                         /*tp_compare*/
    0,                         /*tp_repr*/
    0,                         /*tp_as_number*/
    0,                         /*tp_as_sequence*/
    0,                         /*tp_as_mapping*/
    0,                         /*tp_hash */
    0,                         /*tp_call*/
    0,                         /*tp_str*/
    0,                         /*tp_getattro*/
    0,                         /*tp_setattro*/
    0,                         /*tp_as_buffer*/
    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
    "footprint objects",           /* tp_doc */
    0,		               /* tp_traverse */
    0,		               /* tp_clear */
    0,		               /* tp_richcompare */
    0,		               /* tp_weaklistoffset */
    0,		               /* tp_iter */
    0,		               /* tp_iternext */
    PyApiFootprint_methods,             /* tp_methods */
    0,//members can also be set                         /* tp_members */
    PyApiFootprint_getseters,                         /* tp_getset */
    0,                         /* tp_base */
    0,                         /* tp_dict */
    0,                         /* tp_descr_get */
    0,                         /* tp_descr_set */
    0,                         /* tp_dictoffset */
    0/*(initproc)PyApiFootprint_init*/,      /* tp_init */
    0,                         /* tp_alloc */
    PyApiFootprint_new,                 /* tp_new */
};


